<!--上传文件-->
<template>
	<div>
		<el-upload
			v-bind="allAttrs"
			:id="'c' + columnId"
			name="file"
			:size="mySize"
			:accept="myAccept"
			:action="action"
			:headers="state.myHeaders"
			:data="state.myData"
			:list-type="listType"
			:drag="drag"
			:on-preview="handlePreview"
			:on-remove="handleRemove"
			:on-change="myChange"
			:before-remove="beforeRemove"
			:before-upload="beforeUpload"
			:on-exceed="handleExceed"
			v-model:file-list="myFileList"
			:limit="limit"
			:class="{ hide: myFileList.length >= limit||allAttrs.disabled }"
		>
			<!--  图片上传形式  -->
			<el-icon v-if="type === 'picture'"><Plus /></el-icon>
			<!-- 非图片上传按钮形式  -->
			<el-button v-if="!allAttrs.disabled&&!drag && (type === 'file' || type === 'video')" type="primary">
				<template #icon>
					<el-icon size="16px"><ele-UploadFilled /></el-icon>
				</template>
				{{ btnName }}
			</el-button>
			<!--  非图片上传可拖拽形式  -->
			<el-icon class="el-icon--upload" v-if="drag && (type === 'file' || type === 'video')"><upload-filled /></el-icon>
			<div class="el-upload__text" v-if="drag && (type === 'file' || type === 'video')">将文件拖到此处 ,<em>或点击上传</em></div>
			<template #tip v-if="drag && (type === 'file' || type === 'video')">
				<div class="el-upload__tip">{{ limitDesc }}{{ limit && limit >= 1 ? '，限传' + limit + '个' : '' }}</div>
			</template>

			<template #[item]="data" v-for="item in Object.keys($slots)">
				<slot :name="item" v-bind="data || {}"></slot>
			</template>
			<template #file="{ file }" v-if="props.customFlag" >
				<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
				<span class="el-upload-list__item-actions">
				<span
					class="el-upload-list__item-preview"
					@click="handlePreview(file)"
				>
					<el-icon><zoom-in /></el-icon>
				</span>
				<span
					class="el-upload-list__item-delete"
					@click="handleDownload(file)"
				>
					<el-icon><Download /></el-icon>
				</span>
				<span
					v-if="!allAttrs.disabled"
					class="el-upload-list__item-delete"
					@click="handleRemoveBtn(file)"
				>
					<el-icon><Delete /></el-icon>
				</span>
				</span>
			</template>
		</el-upload>
		<el-dialog v-if="type === 'video'" v-model="dialogVisible">
			<video-play v-bind="options" />
		</el-dialog>
		<el-image-viewer
			v-if="type === 'picture' && dialogVisible"
			:initial-index="checkImgIndex"
			:hide-on-click-modal="true"
			@close="onClose"
			:url-list="showList"
		>
		</el-image-viewer>
	</div>
</template>

<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { reactive, computed, useAttrs, toRefs, ref, onMounted } from 'vue';
import { Plus,Delete, Download, ZoomIn } from '@element-plus/icons-vue';
import { UploadFilled } from '@element-plus/icons-vue';
import { videoPlay } from 'vue3-video-play';
// 引入组件需要的属性、控制类
import { itemProps, itemController } from '../lib/mapController';
import system from '@/api/model/common';
import 'vue3-video-play/dist/style.css';
import { isUrl } from '@/utils/util';
import { Session } from '@/utils/storage';
import { user } from '@/store';
import { getFileSignParams, signFileParams } from '@/utils/signatureUtil';
import { compress, compressAccurately } from 'image-conversion'
const LOCAL_TOKEN_NAME = import.meta.env.VITE_LOCAL_TOKEN_NAME as string;
const ACCESS_TOKEN = import.meta.env.VITE_ACCESS_TOKEN as string;
const VITE_APP_ID = import.meta.env.VITE_APP_ID as string;
// 定义属性
const props = defineProps({
	...itemProps, // 基础属性
	accept: {
		type: [String, Array],
	},
	action: {
		type: [String],
		default: () => {
			return system.fileUploadUrl.url;
		},
	},
	customFlag: {
		type: Boolean,
		default: false,
	},
	//返回类型：url showId
	returnType: {
		type: String,
		default: 'showId',
	},
	//返回格式 string 字符串 多个用英文逗号隔开，array 数组
	modelType: {
		type: String,
		default: 'string',
	},
	type: {
		type: [String],
		default: 'picture',
	},
	fileTypes: {
		type: [String, Array<String>],
		default: '',
	},
	limit: {
		type: [Number],
		default: 9,
	},
	limitDesc: {
		type: String,
		default: '',
	},
	btnName: {
		type: String,
		default: '点击选择上传文件',
	},
	drag: {
		type: Boolean,
		default: false,
	},
	modelValue: [String, Array],
	fileList: [Object, Array],
	headers: {
		type: Object,
		default: () => {
			return {};
		},
	},
	//文件分类
	fileClassCode: {
		type: String,
		default: '99',
	},
	//文件名前缀
	fileNamePrefix: {
		type: String,
		default: '初始化图片',
	},
	// 是否开启压缩上传 true 开启 false 关闭
	compress: {
		type: Boolean,
		default: true
	}, 
});
const flagData = reactive({
	uploadFlag: false,
});
const attrs = useAttrs();
const emit = defineEmits(['update:modelValue', 'update:file-list', 'on-change', 'before-upload']);
const allAttrs = computed(() => {
	return Object.assign(props.extend, attrs);
});
const state = reactive({
	mySize: allAttrs.value.size,
	listType: 'picture-card',
	myHeaders: {} as any,
	myData: {} as any,
});
const { value, globalSize } = itemController(props, allAttrs.value, emit);
const dialogImageUrl = ref('');
const dialogVisible = ref(false);
// 转换允许上传的类型
const myAccept = computed(() => {
	if (Array.isArray(props.accept)) {
		return props.accept.join(',');
	} else {
		return props.accept;
	}
});

if (props.type === 'file' || props.type === 'video') {
	state.listType = 'text';
}

const myFileList = ref([]);
const showList = ref([] as any);
const checkImgIndex = ref(0);
const options = reactive({
	width: '100%', //播放器宽度
	height: '450px', //播放器高度
	color: '#409eff', //主题色
	title: '', //视频名称
	src: 'https://cdn.jsdelivr.net/gh/xdlumia/files/video-play/IronMan.mp4', //视频源
	muted: false, //静音
	webFullScreen: false,
	speedRate: ['0.75', '1.0', '1.25', '1.5', '2.0'], //播放倍速
	autoPlay: false, //自动播放
	loop: false, //循环播放
	mirror: false, //镜像画面
	ligthOff: false, //关灯模式
	volume: 0.3, //默认音量大小
	control: true, //是否显示控制
	controlBtns: ['audioTrack', 'quality', 'speedRate', 'volume', 'setting', 'pip', 'pageFullScreen', 'fullScreen'], //显示所有按钮,
});

// 重新选择文件
const myChange = (file, fileList) => {
	changeFile(file, fileList);
};
const onClose = () => {
	dialogVisible.value = false;
};
const changeFile = (file, fileList) => {
	if (file.percentage === 100) {
		let retList = [] as any;
		let showFileList=[] as any;
		let index=0;
		let list = fileList.map((item) => {
			let fileParam = {} as any;
			let showId = '';
			if (item.showId) {
				showId = item.showId;
			} else {
				if (item.response.code == 0) {
					showId = item.response.result.file.showId;
				} else {
					file.percentage = 0;
					item.percentage = 0;
					ElMessage.warning(item.response.message || '上传失败');
				}
			}
			if (showId) {
				fileParam.showId = showId;
				fileParam.url = item.url;
				fileParam.name = item.name;
				fileParam.size = item.size;
				fileParam.percentage = item.percentage;
				fileParam.status = item.status;
				fileParam.index = index;
				fileParam.uid = item.uid;
				retList.push(fileParam);
				showFileList.push(fileParam.url);
				index=index+1;
			}
			if (props.returnType === 'showId') {
				return showId;
			} else {
				if (showId) {
					return system.fileShowUrl.url + showId;
				} else {
					return '';
				}
			}
		});

		if (props.modelType === 'string' || props.modelType === 'String') {
			let retValue = '';
			list.forEach((item) => {
				retValue += item + ',';
			});
			const reg = /,$/gi;
			retValue = retValue.replace(reg, '');
			value.value = retValue;
		} else {
			value.value = list;
		}
		myFileList.value = retList;
		showList.value = showFileList;
		emit('update:file-list', retList);
		emit('on-change', retList);
	}
};
const handleDownload=(file) => {
	window.open(file.url,"_blank")
}
const handleRemoveBtn = (file) => {
	let list =  myFileList.value.filter((item:any) => item.uid !== file.uid);
	changeFile(file, list);
};
// 删除文件
const handleRemove = (file, fileList) => {
	changeFile(file, fileList);
};
const beforeRemove = (file, fileList) => {
	if (flagData.uploadFlag) {
		flagData.uploadFlag = false;
		return true;
	}
	return ElMessageBox.confirm(`真的要删除 ${file.name} 文件吗？`);
};
// 文件上传前的回调
const beforeUpload = (file: any) => {
	
	let fileName=file.name;
	//获取文件的后缀，获取最后一个点的位置
	let lastIndex = fileName.lastIndexOf('.');
	if(lastIndex==-1){
		flagData.uploadFlag = true;
		ElMessage.warning(`上传的文件类型只能为${props.fileTypes}`);
		return false;
	}
	// 文件类型
	let fileType = fileName.substring(lastIndex+ 1);
	if(fileType){
		fileType = fileType.toLowerCase();
	}
	if (props.fileTypes&&props.fileTypes.length != 0 && props.fileTypes.indexOf(fileType) == -1) {
		flagData.uploadFlag = true;
		ElMessage.warning(`上传的文件类型只能为${props.fileTypes}`);
		return false;
	}
	if(props.type==='picture'){
		//图片格式，判断只能上传图片
		const imageExtensions = ['jpg', 'png', 'gif', 'jpeg', 'webp','svg','tif','bmp','tga','wmf'];
		if(!imageExtensions.includes(fileType)){
			flagData.uploadFlag = true;
			ElMessage.warning(`只能上传图片，可通过手机拍照或电脑截图后上传`);
			return false;
		}
		
	}
	let formData = {
		...allAttrs.value.data,
		uploaderId: user.userId ? user.userId : '',
		uploader: user.fullName ? user.fullName : '',
		fileClassCode: props.fileClassCode,
	};
	state.myData.fileInfo = JSON.stringify(formData);
	const { signature, timestamp } = signFileParams();
	let header = Object.assign({}, props.headers || {});
	const token = Session.get(LOCAL_TOKEN_NAME);
	if (token) {
		header[ACCESS_TOKEN] = token;
	}
	header.appId = VITE_APP_ID;
	header.signature = signature;
	header.timestamp = timestamp + '';
	state.myHeaders = header;
	emit('before-upload', file);
	if(props.compress&&props.type==='picture'){
		//图片需要进行压缩
		return new Promise((resolve, reject) => {
        if (file.size / 1024 > 200) { // 大于 200 kb 就压缩
          compressAccurately(file, 200).then(res => {
            // The res in the promise is a compressed Blob type (which can be treated as a File type) file;
            console.log(res)
            resolve(res)
          })
        } else{
          // 无需压缩直接返回原文件
          resolve(file)
        }
      })
	}
};

const handlePreview = (file) => {
	if (props.type === 'picture') {
		dialogImageUrl.value = file.url;
		dialogVisible.value = true;
		checkImgIndex.value = file.index;
	} else if (props.type === 'video') {
    window.open(file.url,'_self')
	}else if(props.type === 'file'){
		window.open(file.url,"_blank")
	}
};

const handleExceed = (files, fileList) => {
	ElMessage.warning(`文件上传数量限额 ${fileList.length} 个！`);
};

// 初始化
onMounted(() => {
	nextTick(() => {
		//初始化优先使用filelist里面的内容，如果filelist传入，不去初始化modelvalue的内容
    if(props.fileList&&props.fileList.length>0){
      setFileList();
    }else{
      setFile();
    }
    
	});
});
const setFile = () => {
	let defaultFileList = [] as any;
	let showFileList = [] as any;
	if (!myFileList.value || myFileList.value.length <= 0) {
		let list = [] as any;
		if (typeof value.value === 'string') {
			if (value.value) {
				list = value.value.split(',');
			}
		} else {
			if (value.value) {
				list = value.value;
			}
		}

		let index = 0;
		list.forEach((str) => {
			let url = '';
			let showId = '';
			if (isUrl(str, false)) {
				url = str + getFileSignParams();
			} else {
				url = system.fileShowUrl.url + str + getFileSignParams();
				showId = str;
			}
			let fileItem = {
				index: index,
				name: props.fileNamePrefix + (index + 1),
				url: url,
				showId: showId,
				percentage: 100,
				status: 'success',
			};

			showFileList.push(url);
			defaultFileList.push(fileItem);
			index = index + 1;
		});
		myFileList.value = defaultFileList;
		showList.value = showFileList;
	}else{
		let list = [] as any;
		if (typeof value.value === 'string') {
			if (value.value) {
				list = value.value.split(',');
			}
		} else {
			if (value.value) {
				list = value.value;
			}
		}
		let changeFlag=false;
		myFileList.value.forEach(fileItem=>{
			let flag=true;
			list.forEach((str) => {
				if(fileItem.showId===str){
					flag=false;
				}
			})
			if(flag){
				changeFlag=true;
			}
		})
		if(changeFlag){
			
		let index = 0;
		list.forEach((str) => {
			let url = '';
			let showId = '';
			if (isUrl(str, false)) {
				url = str + getFileSignParams();
			} else {
				url = system.fileShowUrl.url + str + getFileSignParams();
				showId = str;
			}
			let fileItem = {
				index: index,
				name: props.fileNamePrefix + (index + 1),
				url: url,
				showId: showId,
				percentage: 100,
				status: 'success',
			};

			showFileList.push(url);
			defaultFileList.push(fileItem);
			index = index + 1;
		});
		myFileList.value = defaultFileList;
		showList.value = showFileList;
		}
	}
};
const setFileList = () => {
	let index = 0;
	let defaultFileList = [] as any;
	let showFileList = [] as any;
	if (props.fileList) {
		let changeFlag=false;
		if(myFileList.value.length<1){
			changeFlag = true
		}
		myFileList.value.forEach(fileItem=>{
			let flag=true;
			props.fileList.forEach((item) => {
				if(fileItem.showId===item.showId){
					flag=false;
				}
			})
			if(flag){
				changeFlag=true;
			}
		})
		if(changeFlag){
			props.fileList.forEach((item: any) => {
			let url = '';
			let showId = '';
			if (item.url) {
				if (isUrl(item.url, false)) {
					url = item.url + getFileSignParams();
				}else{
					url = item.url;
				}
				
				showId = item.showId;
			} else {
				if (item.showId) {
					url = system.fileShowUrl.url + item.showId + getFileSignParams();
					showId = item.showId;
				}
			}
			let fileItem = {
				index: index,
				name: item.fileName ? item.fileName : props.fileNamePrefix + (index + 1),
				url: url,
				showId: showId,
				percentage: item.percentage ? item.percentage : 100,
				status: item.status ? item.status : 'success',
				size: item.size,
			};

			showFileList.push(url);
			defaultFileList.push(fileItem);
			index = index + 1;
		});
		myFileList.value = defaultFileList;
		showList.value = showFileList;
		}
		
	}
};
globalSize(state);
// 输出
const { mySize, listType } = toRefs(state);
// 监听路由的变化，设置网站标题
watch(
	() => props.modelValue,
	() => {
		value.value = props.modelValue;
		setFile();
	},
	{
		deep: true,
	}
);
watch(
	() => props.fileList,
	() => {
		setFileList();
	},
	{
		deep: true,
	}
);
</script>
<script lang="ts">
// 声明额外的选项
export default {
	name: 'zh-upload',
	inheritallAttrs: false,
};
</script>
<style>
.hide .el-upload--picture-card {
	display: none;
}
</style>
